package com.edu.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.edu.compile.AbstractCompileResult;
import com.edu.compile.CompileContainer;
import com.edu.dao.EventDefineMapper;
import com.edu.dao.EventNodeMapper;
import com.edu.dao.EventVersionMapper;
import com.edu.model.EventDefine;
import com.edu.model.EventNode;
import com.edu.model.EventVersion;
import com.edu.model.Response;
import com.edu.model.constant.EventConstant;
import com.edu.model.constant.ResultMsgConstant;
import com.edu.model.dto.EventDefineDto;
import com.edu.model.dto.NodeMetadata;
import com.edu.model.util.DateUtil;
import com.edu.service.EventDefineService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StopWatch;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class EventDefineServiceImpl implements EventDefineService {

    private static final Logger LOGGER = LoggerFactory.getLogger(EventDefineServiceImpl.class);

    @Resource
    private EventDefineMapper eventDefineMapper;

    @Resource
    private EventVersionMapper eventVersionMapper;

    @Resource
    private EventNodeMapper eventNodeMapper;

    @Transactional
    @Override
    public Response saveEventDefine(EventDefineDto eventDefineDto) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        try {
            if (eventDefineDto == null) {
                LOGGER.error("方法调用参数不能为null");
                return Response.fail("参数不能为null");
            }
            EventDefine eventDefine = new EventDefine();
            eventDefine.setImplType(eventDefineDto.getImplType());
            EventDefine oldEventDefine = null;
            if (eventDefineDto.getEventId() == null) {
                eventDefine.setStatus(EventConstant.OperateType.NEW_STATE);
                eventDefine.setVersion(0);
            } else {
                oldEventDefine = eventDefineMapper.get(eventDefineDto.getEventId());
                if (oldEventDefine == null) {
                    eventDefineDto.setEventId(null);
                    eventDefine.setVersion(0);
                } else {
                    eventDefine.setEventId(oldEventDefine.getEventId());
                    eventDefine.setVersion(oldEventDefine.getVersion());
                }
            }

            eventDefine.setEventName(eventDefineDto.getEventName());
            Date now = DateUtil.getNow();
            List<EventNode> nodes = new ArrayList<>(eventDefineDto.getNodes().size());
            EventNode eventNode;
            int index = 0;
            boolean httpEvent = false;
            boolean hasLoop = false;
            boolean hasLoopEnd = false;
            String actionInput = "";

            for (NodeMetadata baseDto : eventDefineDto.getNodes()) {
                // TODO
                if (baseDto.getNodeType() == EventConstant.NodeTypeConstant.LOOP + "") {
                    if (!hasLoop) {
                        hasLoop = true;
                    } else {
                        return Response.fail("事件只能包含一个循环开始");
                    }
                    // TODO
                } else if (baseDto.getNodeType() == EventConstant.NodeTypeConstant.LOOP_END + "") {
                    if (!hasLoopEnd) {
                        hasLoopEnd = true;
                    } else {
                        return Response.fail("事件只能包含一个循环结束");
                    }
                }
                index++;
                eventNode = parseEventNode(baseDto, eventDefineDto.getEventId());
                eventNode.setCreateTime(now);
                eventNode.setSorted(index);
                nodes.add(eventNode);
                // TODO
                if (baseDto.getNodeType() == EventConstant.NodeTypeConstant.HTTP + "") {
                    httpEvent = true;
                    actionInput = baseDto.getConfig();
                }
            }

            if ((hasLoop && !hasLoopEnd) || (!hasLoop && hasLoopEnd)) {
                return Response.fail("循环开始和循环结束必须成对出现");
            }

            Response checkActionResponse = checkAction(eventDefineDto.getEventId(), actionInput, httpEvent);
            if (checkActionResponse.isFail()) {
                return checkActionResponse;
            }

            eventDefine.setAction(checkActionResponse.parse());
            eventDefine.setCreateTime(now);
            eventDefine.setUpdateTime(now);
            eventDefine.setLines(eventDefineDto.getLines());
            eventDefineMapper.insert(eventDefine);

            if (eventDefineDto.getEventId() == null) {
                eventDefineDto.setEventId(eventDefine.getEventId());
                for (EventNode node : nodes) {
                    node.setEventId(eventDefine.getEventId());
                }
            }

            eventNodeMapper.deleteByEventId(eventDefine.getEventId());
            //保存新节点
            eventNodeMapper.insertList(nodes);

            Response compile = compile(eventDefine, eventDefineDto.getNodes(), eventDefineDto.getLang());
            if (compile.isFail()) {
                setCompileErrorEventStatus(eventDefine, oldEventDefine);
                eventDefineMapper.update(eventDefine);
                return compile;
            }

            setEventStatus(eventDefine, oldEventDefine);
            eventDefineMapper.update(eventDefine);

            EventVersion eventVersion = initEventVersion(eventDefine, compile.parse(), eventDefineDto.getLang(), now);
            eventVersionMapper.insertOrUpdate(eventVersion);

            return Response.success(ResultMsgConstant.COMPILED);
        } finally {
            stopWatch.stop();
            LOGGER.info("event save cost {} ms", stopWatch.getLastTaskTimeMillis());
        }
    }

    private void setCompileErrorEventStatus(EventDefine eventDefine, EventDefine oldEventDefine) {
        if (oldEventDefine != null) {
            switch (oldEventDefine.getStatus()) {
                case EventConstant.OperateType.RUNNING_STATE: {
                }
                case EventConstant.OperateType.RECOMPILED_AT_RUNNING_STATE: {
                }
                case EventConstant.OperateType.COMPILE_FAILED_AT_RUNNING_STATE: {
                    eventDefine.setStatus(EventConstant.OperateType.COMPILE_FAILED_AT_RUNNING_STATE);
                    break;
                }
                default: {
                    eventDefine.setStatus(EventConstant.OperateType.COMPILED_STATE);
                    break;
                }
            }
        } else {
            eventDefine.setStatus(EventConstant.OperateType.COMPILE_FAILED_STATE);
        }
    }

    private void setEventStatus(EventDefine eventDefine, EventDefine oldEventDefine) {
        if (oldEventDefine != null) {
            switch (oldEventDefine.getStatus()) {
                // 当前状态运行中、运行中（有新版本）、运行中（编译异常），状态变为运行中（有新版本）
                case EventConstant.OperateType.RUNNING_STATE: {
                }
                case EventConstant.OperateType.RECOMPILED_AT_RUNNING_STATE: {
                }
                case EventConstant.OperateType.COMPILE_FAILED_AT_RUNNING_STATE: {
                    eventDefine.setStatus(EventConstant.OperateType.RECOMPILED_AT_RUNNING_STATE);
                    break;
                }
                default: {
                    eventDefine.setStatus(EventConstant.OperateType.COMPILED_STATE);
                    break;
                }
            }
        } else {
            eventDefine.setStatus(EventConstant.OperateType.COMPILED_STATE);
        }
    }

    private EventVersion initEventVersion(EventDefine eventDefine, AbstractCompileResult abstractCompileResult, String lang, Date now) {
        EventVersion eventVersion = new EventVersion();
        eventVersion.setCreateTime(eventDefine.getCreateTime());
        eventVersion.setUpdateTime(now);
        eventVersion.setVersion(eventDefine.getVersion());
        eventVersion.setEventId(eventDefine.getEventId());
        eventVersion.setLayout(eventDefine.getLines());
        eventVersion.setAction(eventDefine.getAction());
        eventVersion.setDataSource(abstractCompileResult.getDataSourceList());
        eventVersion.setStorePath(abstractCompileResult.getStorePath());
        eventVersion.setLang(lang);
        return eventVersion;
    }

    private Response compile(EventDefine eventDefine, List<NodeMetadata> nodeMetadataList, String lang) {
        CompileContainer compileContainer = new CompileContainer();
        compileContainer.init(eventDefine.getEventId(), nodeMetadataList);
        Response compile = compileContainer.compile();
        return compile;
    }

    private Response checkAction(String eventId, String actionInput, boolean httpEvent) {

        if (!httpEvent) {
            return Response.success(actionInput, null);
        }

        if (StringUtils.isBlank(actionInput)) {
            return Response.fail("action不能为null");
        }

        JSONObject input = JSON.parseObject(actionInput);
        String action = input.getString("action");
        action = action.trim();
        action = action.replaceAll(EventConstant.Patterns.ACTION_START, "").replaceAll(EventConstant.Patterns.ACTION_END, "");
        int checkAction = eventDefineMapper.checkAction(action, eventId);
        if (checkAction > 0) {
            return Response.fail("action不能重复");
        }
        return Response.success(action);
    }

    private EventNode parseEventNode(NodeMetadata baseDto, String eventId) {
        EventNode eventNode = new EventNode();
        eventNode.setNodeId(baseDto.getNodeId());
        eventNode.setNodeName(baseDto.getNodeName());
        eventNode.setParentNodeId(baseDto.getParentNodeId() == null ? null : baseDto.getParentNodeId());
        eventNode.setEventId(eventId);
        eventNode.setConfig(baseDto.getConfig());
        eventNode.setNodeType(baseDto.getNodeType());
        return eventNode;
    }
}
